using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WPCoco;
using Microsoft.Xna.Framework;
using WPCoco.Controllers;
using Microsoft.Xna.Framework.Input.Touch;
using WPCoco.Tasks;

namespace WPCoco.Specialized
{
    public class ListViewLayer : LocalizedNode
    {
        public ListViewLayer()
        {
            this.IsRunningChange += new EventHandler(PagedScene_IsRunningChange);

            baseLayer = new ListViewRollingLayer(this);
            AddNode(baseLayer, int.MinValue);

            Width = 100; Height = 100;
        }

        ListViewRollingLayer baseLayer;

        #region Input

        void PagedScene_IsRunningChange(object sender, EventArgs e)
        {
            if (IsRunning)
                ConnectToTouchScreen();
            else
                DisconnectFromTouchScreen();
        }

        void ConnectToTouchScreen()
        {
            ControllerManager.Shared.TouchScreen.StartDrag += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_StartDrag);
            ControllerManager.Shared.TouchScreen.Dragging += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_Dragging);
            ControllerManager.Shared.TouchScreen.EndDrag += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_EndDrag);
        }

        void DisconnectFromTouchScreen()
        {
            ControllerManager.Shared.TouchScreen.StartDrag -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_StartDrag);
            ControllerManager.Shared.TouchScreen.Dragging -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_Dragging);
            ControllerManager.Shared.TouchScreen.EndDrag -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_EndDrag);
        }

        Vector2 downPoint; float startOffset; bool down;

        bool IsInside(Vector2 p)
        {
            Matrix m = MatrixHelper.GetViewWorldMatrix(this);
            Vector2.Transform(ref p, ref m, out p);
            RectangleF rect = new RectangleF(0, 0, Width, Height);
            return rect.Contains(p);
        }

        void TouchScreen_StartDrag(object sender, CustomEventArgs<GestureSample> e)
        {
            if (!IsInside(e.Value.Position)) return;
            down = true;
            StopAnimation();
            startOffset = offset;
            downPoint = e.Value.Position;
        }

        void TouchScreen_Dragging(object sender, CustomEventArgs<GestureSample> e)
        {
            if (!down) return;
            Vector2 delta = e.Value.Position - downPoint;

            Matrix m = MatrixHelper.GetViewWorldMatrix(this);
            delta = Vector2.TransformNormal(delta, m);

            Offset = startOffset + delta.Y;
        }

        void TouchScreen_EndDrag(object sender, CustomEventArgs<GestureSample> e)
        {
            if (!down) return;
            down = false;
            StopAnimation();
            if (offset > 0) 
            {
                float time = offset / 200;
                movingTask = new EaseExponentialOut(new FloatAnimation("Offset", offset, 0, time));
                RunTask(movingTask);
                return;
            }
            if (items.Count == 0) return;
            ListViewItem lastItem = items[items.Count - 1];
            float limit = Math.Min(Height, lastItem.Position.Y + lastItem.Height + itemSpacing);
            float last = lastItem.Position.Y + lastItem.Height + itemSpacing + offset;
            if (last < limit) 
            {
                last = limit - last + offset;
                float time = Math.Abs(offset - last) / 200;
                movingTask = new EaseExponentialOut(new FloatAnimation("Offset", offset, last, time));
                RunTask(movingTask);
            }
        }

        #endregion

        Task movingTask = null;

        void StopAnimation() 
        {
            if (movingTask == null) return;
            movingTask.Stop();
        }

        float offset = 0;

        public float Offset
        {
            get { return offset; }
            set
            {
                offset = value;
                baseLayer.Position = new Vector2(0, offset);
            }
        }

        int identationSpace = 20;

        public int IdentationSpace
        {
            get { return identationSpace; }
            set { identationSpace = value; }
        }

        int itemSpacing = 3;

        public int ItemSpacing
        {
            get { return itemSpacing; }
            set { itemSpacing = value; }
        }

        List<ListViewItem> items = new List<ListViewItem>();

        public void AddItem(ListViewItem item) 
        {
            item.ListView = this;
            items.Add(item);
            baseLayer.AddNode(item, int.MinValue);
            ArrangeItems();
        }

        public void RemoveItem(ListViewItem item) 
        {
            item.ListView = null;
            items.Remove(item);
            baseLayer.RemoveNode(item);
            ArrangeItems();
        }

        public void Clear() 
        {
            for (int i = 0; i < items.Count; i++)
            {
                items[i].ListView = null;
                baseLayer.RemoveNode(items[i]);
            }
            items.Clear();
            ArrangeItems();
        }

        public int Count { get { return items.Count; } }

        public ListViewItem this[int index]
        {
            get { return items[index]; }
            set 
            {
                if (value == items[index]) return;
                baseLayer.RemoveNode(items[index]);
                items[index].ListView = null;
                if (value != null)
                {
                    items[index] = value;
                    baseLayer.AddNode(value);
                    value.ListView = null;
                }
                else 
                {
                    items.RemoveAt(index);
                }
                ArrangeItems();
            }
        }

        public void ArrangeItems() 
        {
            float x = 0; float y = 0;
            ListViewItem item;
            for (int i = 0; i < items.Count; i++)
            {
                item = items[i];
                item.Position = new Vector2(x + identationSpace * item.Identation, y);
                y += item.Height + itemSpacing;
            }
        }

        internal bool IsItemViewed(ListViewItem item)
        {
            float y = item.Position.Y;
            if (y + item.Height + offset < 0 || y + offset > Height) return false;
            return true;
        }
    }

    class ListViewRollingLayer : LocalizedNode 
    {
        public ListViewRollingLayer(ListViewLayer layer)
        {

        }
    }
}
